/**
 * 空闲状态检测器，用于检测指定时间内无消息时触发自定义操作
 * @example
 * const checker = new IdleChecker({ idleThreshold: 300 }); // 300ms 阈值
 * checker.setIdleCallback(() => console.log("空闲触发"));
 * checker.start();
 */
export default class IdleChecker {
  /** 最后一次收到消息的时间戳（私有） */
  private lastMessageTime: number = 0;
  /** 是否已触发过空闲操作（私有，避免重复触发） */
  private hasTriggered: boolean = false;
  /** RAF 回调 ID（公有，用于清理） */
  public rafId: number = 0;
  /** 空闲时触发的回调函数（私有，支持外部注入） */
  private idleCallback: (() => void) | null = null;
  /** 空闲检测阈值（单位：ms，默认 200ms） */
  private readonly idleThreshold: number;

  /**
   * 构造函数
   * @param options 配置项
   * @param options.idleThreshold 空闲检测阈值（ms），默认 200
   */
  constructor(options: { idleThreshold?: number } = {}) {
    this.idleThreshold = options.idleThreshold ?? 200;
  }

  /**
   * 核心检测逻辑（私有）
   * - 检查是否超过阈值未收到消息
   * - 安全执行空闲回调（防空值/防错误）
   */
  private checkIdle = () => {
    const currentTime = Date.now();
    const isIdle = currentTime - this.lastMessageTime >= this.idleThreshold;
    // 仅当满足空闲条件且未触发过时执行
    if (isIdle && !this.hasTriggered) {
      this.hasTriggered = true;
      try {
        // 安全调用：检查回调存在性
        this.idleCallback?.();
      } catch (error) {
        console.error("执行空闲回调时发生错误:", error);
      }
    }

    // 递归调用 RAF 继续检测（绑定 this 避免丢失上下文）
    this.rafId = window.requestAnimationFrame(this.checkIdle);
  };

  /**
   * 启动空闲检测
   * - 自动清理旧的 RAF 循环（防重复）
   */
  start() {
    this.stop(); // 先停止已有检测
    this.rafId = window.requestAnimationFrame(this.checkIdle);
    console.log("空闲检测已启动");
  }

  /**
   * 停止空闲检测
   * - 清理 RAF 循环
   * - 重置触发状态（可选）
   */
  stop() {
    if (this.rafId) {
      window.cancelAnimationFrame(this.rafId);
      this.rafId = 0; // 重置 ID
    }
    // 可选：是否需要在停止时重置触发状态？根据业务需求决定
    // this.hasTriggered = false;
  }

  /**
   * 更新最后一次消息时间（供外部调用）
   * - 收到新消息时调用，重置检测状态
   */
  updateLastMessageTime() {
    this.lastMessageTime = Date.now();
    this.hasTriggered = false; // 重置触发状态
  }

  /**
   * 设置空闲时触发的回调（关键解耦接口）
   * @param callback 空闲时执行的函数（可为 null 取消回调）
   */
  setIdleCallback(callback: (() => void) | null) {
    this.idleCallback = callback;
  }

  /**
   * 销毁检测器（生命周期方法）
   * - 停止检测并清理所有资源
   * - 建议在组件卸载时调用
   */
  destroy() {
    this.stop();
    this.idleCallback = null; // 解除回调引用（防内存泄漏）
    this.lastMessageTime = 0;
    this.hasTriggered = false;
  }
}
